/* Includes */
#include <unistd.h>     /* Symbolic Constants */
#include <sys/types.h>  /* Primitive System Data Types */ 
#include <errno.h>      /* Errors */
#include <stdio.h>      /* Input/Output */
#include <sys/wait.h>   /* Wait for Process Termination */
#include <stdlib.h>     /* General Utilities */
#include "hw2_syscalls.h"
#include <sched.h> 

int GetBehaviorId() {
	int forkRes = fork();
	int i;
	if (forkRes < 0) {
		exit(0);
	}
	else if (forkRes == 0) {
		return 0;
	}
	else {
		wait(&i);
		forkRes = fork();
		if (forkRes < 0) {
			exit(0);
		}
		else if (forkRes == 0) {
			return 1;
		}
		else {
			wait(&i);
			forkRes = fork();
			if (forkRes < 0) {
				exit(0);
			}
			else if (forkRes == 0) {
				return 2;
			}
			else {
				wait(&i);
				return 3;
			}
		}
	}
}

// Tests that forking a BRR creates a BRR
void Test0() {
	int test = 0;
    pid_t childpid; /* variable to store the child's pid */
    int retval;     /* child process: user-provided return code */
    int status;     /* parent process: child's exit status */
    /* only 1 int variable is needed because each process would have its
       own instance of the variable
       here, 2 int variables are used for clarity */
        
        
    struct sched_param param;
    param.sched_priority=0;
    param.trials=5;
    pid_t pid = getpid();
    int x=sched_setscheduler(pid,SCHED_BRR,&param);        
    printf("TEST%d: is_brr: %d\n",test,is_brr(pid));
    /* now create new process */
    childpid = fork();
    
    if (childpid >= 0) /* fork succeeded */
    {
        if (childpid == 0) /* fork() returns 0 to the child process */
        {
            printf("TEST%d: CHILD: I am the child process!\n",test);
            printf("TEST%d: TEST1: CHILD: Here's my PID: %d\n",test, getpid());
            printf("TEST%d: CHILD: My parent's PID is: %d\n",test, getppid());
            printf("TEST%d: CHILD: The value of my copy of childpid is: %d\n",test, childpid);
            printf("TEST%d: CHILD: Am I BRR: %d\n",test,is_brr(getpid()));
            int M = 50000;
            int k,m,a=0;
            for(k=0;k<M;k++){
            	for(m=0;m<M;m++){
            		a = 7 * a + 13;
            	}
            }
            printf("TEST%d: CHILD: Am I BRR: %d\n",test,is_brr(getpid()));
            printf("TEST%d: CHILD: Sleeping for 1 second...\n",test);
            sleep(1); /* sleep for 1 second */
            printf("TEST%d: CHILD: Enter an exit value (0 to 255): ",test);
            scanf(" %d", &retval);
            printf("TEST%d: CHILD: Goodbye!\n",test);    
            exit(retval); /* child exits with user-provided return code */
        }
        else /* fork() returns new pid to the parent process */
        {
            printf("TEST%d: PARENT: I am the parent process!\n",test);
            printf("TEST%d: PARENT: Here's my PID: %d\n",test, getpid());
            printf("TEST%d: PARENT: The value of my copy of childpid is %d\n",test, childpid);
            printf("TEST%d: PARENT: AM I BRR: %d\n",test,is_brr(getpid()));
            printf("TEST%d: PARENT: I will now wait for my child to exit.\n",test);
            wait(&status); /* wait for child to exit, and store its status */
            printf("TEST%d: PARENT: Child's exit code is: %d\n",test, WEXITSTATUS(status));
            printf("TEST%d: PARENT: Goodbye!\n",test);             
            exit(0);  /* parent exits */       
        }
    }
    else /* fork returns -1 on failure */
    {
        perror("fork"); /* display error message */
        exit(0); 
    }
}

// Tests that forking an OD_BRR creates an OD_BRR
void Test1() {
	int test = 1;
    pid_t childpid; /* variable to store the child's pid */
    int retval;     /* child process: user-provided return code */
    int status;     /* parent process: child's exit status */
    /* only 1 int variable is needed because each process would have its
       own instance of the variable
       here, 2 int variables are used for clarity */
        
        
    struct sched_param param;
    param.sched_priority=0;
    param.trials=5;
    pid_t pid = getpid();
    int x=sched_setscheduler(pid,SCHED_BRR,&param);        
    printf("is_brr: %d\n",is_brr(pid));
	
	int M = 50000;
	int k,m,a=0;
	for(k=0;k<M;k++){
		for(m=0;m<M;m++){
			a = 7 * a + 13;
		}
	}	
			
    /* now create new process */
    childpid = fork();
    
    if (childpid >= 0) /* fork succeeded */
    {
        if (childpid == 0) /* fork() returns 0 to the child process */
        {
            printf("TEST%d: CHILD: I am the child process!\n",test);
            printf("TEST%d: TEST1: CHILD: Here's my PID: %d\n",test, getpid());
            printf("TEST%d: CHILD: My parent's PID is: %d\n",test, getppid());
            printf("TEST%d: CHILD: The value of my copy of childpid is: %d\n",test, childpid);
            printf("TEST%d: CHILD: Am I BRR: %d\n",test,is_brr(getpid()));
            printf("TEST%d: CHILD: Sleeping for 1 second...\n",test);
            sleep(1); /* sleep for 1 second */
            printf("TEST%d: CHILD: Enter an exit value (0 to 255): ",test);
            scanf(" %d", &retval);
            printf("TEST%d: CHILD: Goodbye!\n",test);    
            exit(retval); /* child exits with user-provided return code */
        }
        else /* fork() returns new pid to the parent process */
        {
            printf("TEST%d: PARENT: I am the parent process!\n",test);
            printf("TEST%d: PARENT: Here's my PID: %d\n",test, getpid());
            printf("TEST%d: PARENT: The value of my copy of childpid is %d\n",test, childpid);
            printf("TEST%d: PARENT: AM I BRR: %d\n",test,is_brr(getpid()));
            printf("TEST%d: PARENT: I will now wait for my child to exit.\n",test);
            wait(&status); /* wait for child to exit, and store its status */
            printf("TEST%d: PARENT: Child's exit code is: %d\n",test, WEXITSTATUS(status));
            printf("TEST%d: PARENT: Goodbye!\n",test);             
            exit(0);  /* parent exits */       
        }
    }
    else /* fork returns -1 on failure */
    {
        perror("fork"); /* display error message */
        exit(0); 
    }
}

// Tests that forking an BRR keeps trials
void Test2() {
	int test = 2;
    pid_t childpid; /* variable to store the child's pid */
    int retval;     /* child process: user-provided return code */
    int status;     /* parent process: child's exit status */
    /* only 1 int variable is needed because each process would have its
       own instance of the variable
       here, 2 int variables are used for clarity */
        
        
    struct sched_param param;
    param.sched_priority=0;
    param.trials=5;
    pid_t pid = getpid();
    int x=sched_setscheduler(pid,SCHED_BRR,&param);        
    printf("is_brr: %d\n",is_brr(pid));
	
	int M = 2000;
	int k,m,a=0;
	for(k=0;k<M;k++){
		for(m=0;m<M;m++){
			a = 7 * a + 13;
		}
	}	
			
    /* now create new process */
    childpid = fork();
    
    if (childpid >= 0) /* fork succeeded */
    {
        if (childpid == 0) /* fork() returns 0 to the child process */
        {
            printf("TEST%d: CHILD: I am the child process!\n",test);
            printf("TEST%d: TEST1: CHILD: Here's my PID: %d\n",test, getpid());
            printf("TEST%d: CHILD: My parent's PID is: %d\n",test, getppid());
            printf("TEST%d: CHILD: The value of my copy of childpid is: %d\n",test, childpid);
            printf("TEST%d: CHILD: Am I BRR: %d\n",test,is_brr(getpid()));
            int M = 50000;
            int k,m,a=0;
            for(k=0;k<M;k++){
            	for(m=0;m<M;m++){
            		a = 7 * a + 13;
            	}
            }
            printf("TEST%d: CHILD: Am I BRR: %d\n",test,is_brr(getpid()));
            printf("TEST%d: CHILD: Sleeping for 1 second...\n",test);
            sleep(1); /* sleep for 1 second */
            printf("TEST%d: CHILD: Enter an exit value (0 to 255): ",test);
            scanf(" %d", &retval);
            printf("TEST%d: CHILD: Goodbye!\n",test);    
            exit(retval); /* child exits with user-provided return code */
        }
        else /* fork() returns new pid to the parent process */
        {
            printf("TEST%d: PARENT: I am the parent process!\n",test);
            printf("TEST%d: PARENT: Here's my PID: %d\n",test, getpid());
            printf("TEST%d: PARENT: The value of my copy of childpid is %d\n",test, childpid);
            printf("TEST%d: PARENT: AM I BRR: %d\n",test,is_brr(getpid()));
            printf("TEST%d: PARENT: I will now wait for my child to exit.\n",test);
            wait(&status); /* wait for child to exit, and store its status */
            printf("TEST%d: PARENT: Child's exit code is: %d\n",test, WEXITSTATUS(status));
            printf("TEST%d: PARENT: Goodbye!\n",test);             
            exit(0);  /* parent exits */       
        }
    }
    else /* fork returns -1 on failure */
    {
        perror("fork"); /* display error message */
        exit(0); 
    }
}

int main()
{
	int testId = GetBehaviorId();
	switch (testId) {
		case 0:
			Test0();
		case 1:
			Test1();
		case 2:
			Test2();
		case 3:
			//Test3();
	}
	return 0;
}
